package cn.silver.module.system.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.ObjectUtil;
import cn.silver.framework.core.constant.CacheNames;
import cn.silver.framework.core.exception.AuthException;
import cn.silver.framework.core.utils.MapstructUtils;
import cn.silver.framework.mybatis.service.impl.DataServiceImpl;
import cn.silver.framework.openapi.constant.ResultEnum;
import cn.silver.framework.satoken.utils.LoginHelper;
import cn.silver.module.authority.bean.RoleBean;
import cn.silver.module.system.bean.UserBean;
import cn.silver.module.system.domain.SysUser;
import cn.silver.module.system.domain.SysUserPost;
import cn.silver.module.system.domain.SysUserRole;
import cn.silver.framework.mybatis.enums.RoleTypeEnums;
import cn.silver.module.system.mapper.SysUserMapper;
import cn.silver.module.system.models.UserModel;
import cn.silver.module.system.param.PasswordParam;
import cn.silver.module.system.param.UserParam;
import cn.silver.module.system.service.ISysUserPostService;
import cn.silver.module.system.service.ISysUserRoleService;
import cn.silver.module.system.service.ISysUserService;
import cn.silver.module.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;

/**
 * 用户 业务层处理
 *
 * @author Silver Zhou
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends DataServiceImpl<SysUserMapper, SysUser, UserParam, UserBean> implements ISysUserService, UserService {

    private static final String DEFAULT_PASSWORD = "123456";
    private final ISysUserRoleService roleService;
    private final ISysUserPostService postService;

    @Override
    public String init() {
        SysUser user = this.baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getCode, "sysadmin"));
        if (user == null) {
            user = SysUser.getSysadmin();
            user.setPassword(BCrypt.hashpw(user.getCode() + "@" + DEFAULT_PASSWORD));
            this.baseMapper.insert(user);
        }
        return user.getId();
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
    public UserModel selectModelById(String userId) {
        UserBean bean = baseMapper.selectVoById(userId);
        return ObjectUtil.isNull(bean) ? null : MapstructUtils.convert(bean, UserModel.class);
    }

    /**
     * 注册用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(UserParam user, String tenantId) {
        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
        return baseMapper.insert(sysUser) > 0;
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int updateUserProfile(UserParam user) {
        return baseMapper.update(null,
                new LambdaUpdateWrapper<SysUser>()
                        .set(ObjectUtil.isNotNull(user.getName()), SysUser::getName, user.getName())
                        .set(SysUser::getMobile, user.getMobile())
                        .set(SysUser::getEmail, user.getEmail())
                        .eq(SysUser::getId, user.getId()));
    }

    /**
     * 重置用户密码
     *
     * @param userIds 用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void resetUserPwd(Collection<String> userIds) {
        List<SysUser> users = this.baseMapper.selectBatchIds(userIds);
        for (SysUser user : users) {
            user.setPassword(BCrypt.hashpw(user.getCode() + "@" + DEFAULT_PASSWORD));
        }
        baseMapper.updateBatchById(users);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updatePwd(PasswordParam param) {
        if (StringUtils.isBlank(param.getOldPassword())) {
            throw new AuthException("旧密码不能为空");
        }
        SysUser user = this.baseMapper.selectById(LoginHelper.getUserId());
        if (!BCrypt.checkpw(param.getOldPassword(), user.getPassword())) {
            throw new AuthException("旧密码不正确");
        }
        if (!BCrypt.checkpw(param.getNewPassword(), user.getPassword())) {
            throw new AuthException("旧密码不能和新密码一样");
        }
        this.baseMapper.update(new LambdaUpdateWrapper<SysUser>().set(SysUser::getPassword, BCrypt.hashpw(param.getNewPassword())).eq(SysUser::getId, user.getId()));
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean delete(String userId) {
        if (!LoginHelper.isSuperAdmin()) {
            List<RoleBean> roles = this.roleService.selectRoleGroup(userId);
            roles = roles.stream().filter(item -> RoleTypeEnums.SUPER_ROLE.getCode().equalsIgnoreCase(item.getType())).toList();
            if (CollectionUtils.isNotEmpty(roles)) {
                throw new AuthException(ResultEnum.PERM_NOT_CLOUD.getCode(), "不允许删除管理员用户");
            }
        }
        // 删除用户与角色关联
        roleService.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
        // 删除用户与岗位表
        postService.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
        return SqlHelper.retBool(baseMapper.deleteById(userId));
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteBatch(Collection<String> userIds) {
        if (!LoginHelper.isSuperAdmin()) {
            LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(SysUser::getId, userIds);
            wrapper.exists("select 1 from sys_user_role ur left join sys_role r on ur.role_id = r.id "
                    + "where ur.user_id = sys_user.id and r.type = {0}", RoleTypeEnums.SUPER_ROLE.getCode());
            List<UserBean> beans = this.baseMapper.selectVoList(wrapper);
            if (CollectionUtils.isNotEmpty(beans)) {
                throw new AuthException(ResultEnum.PERM_NOT_CLOUD.getCode(), "不允许删除管理员用户");
            }
        }
        // 删除用户与角色关联
        roleService.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, userIds));
        // 删除用户与岗位表
        postService.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, userIds));
        // 防止更新失败导致的数据删除
        baseMapper.deleteByIds(userIds);
    }
}
